<script setup lang="ts">
// 独立“旗标”表单 Marker 组件
// 功能：
// 1) start(): 绑定地图点击事件，允许用户点击地图放置旗标，并将点位夹取在限制区域内
// 2) cancel(): 取消并清理事件与旗标
// 3) query(): 向父组件 emits 三个表单项 + 当前点经纬度
// 依赖：Mapbox GL（项目已有）、weatherStore.map 为地图实例

import { onBeforeUnmount, reactive, ref, computed, nextTick, defineEmits, defineProps, defineExpose } from 'vue'
import mapboxgl, { Map, LngLatLike } from 'mapbox-gl'
import { useWeatherStore } from '@/store'

// ====== Props & Emits ======
// areaPoints: 四点坐标（按 [lng, lat]，顺序不限，通常为 lt/rt/rb/lb 矩形四角）
// 也可传入超过 4 个点，此处仅用于经纬度范围夹取（按轴对齐矩形处理）
const props = defineProps<{
  areaPoints: Array<[number, number]>
  defaultSpeed?: number
  defaultDuration?: number
  loading: boolean
}>()

const emit = defineEmits<{
  (e: 'confirm', payload: { startTime: string; speed: number; duration: number; lng: number; lat: number }): void
  (e: "update:loading", visible: boolean): void;
  (e: 'cancel'): void
  (e: 'close'): void
}>()

const loading = computed({
  get() {
    return props.loading;
  },
  set(visible: boolean) {
    emit("update:loading", visible);
  },
});

const weatherStore = useWeatherStore()

// ====== 内部状态 ======
const form = reactive({
  // 默认当前整点时间
  startTime: (() => {
    const d = new Date()
    d.setMinutes(0, 0, 0)
    // 输入控件使用 datetime-local，需要格式为 YYYY-MM-DD HH:mm
    const pad = (n: number) => String(n).padStart(2, '0')
    const s = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`
    return s
  })(),
  // 数值类字段采用字符串存储，便于前端格式控制（两位小数）
  speed: (props.defaultSpeed ?? 12).toFixed(2),
  duration: (props.defaultDuration ?? 12).toFixed(2),
})

// 仅使用 Popup 承载旗面与底部圆点（不再单独使用 Marker）
let marker: mapboxgl.Marker | null = null // deprecated: 保留变量占位但不再使用
let popup: mapboxgl.Popup | null = null
const popupRef = ref<HTMLDivElement | null>(null)
const datePickerRef = ref<any>(null)

const active = ref(false)  // 是否进入拾取模式
const shown = ref(false)   // 首次点击后才渲染 DOM

// 是否已绑定点击事件
let listening = false

// 当前点位
const currentLngLat = ref<{ lng: number; lat: number } | null>(null)

// ====== 区域夹取工具（含跨 180° 处理） ======
// 说明：
// - 仅按轴对齐矩形进行夹取（从四点求 min/max）
// - 若范围跨越反日界线（宽度 > 180°），则在 [0,360) 展开域内执行经度夹取
const normLon = (lon: number) => {
  let x = lon
  while (x > 180) x -= 360
  while (x < -180) x += 360
  return x
}
const to360 = (lon: number) => (lon < 0 ? lon + 360 : lon)
const clamp = (v: number, a: number, b: number) => (v < a ? a : v > b ? b : v)

const regionStats = computed(() => {
  const pts = (props.areaPoints?.length ? props.areaPoints : [[-180, -90], [180, 90]]) as [number, number][]
  const lats = pts.map((p) => p[1])
  const lons = pts.map((p) => normLon(p[0]))
  const latMin = Math.min(...lats)
  const latMax = Math.max(...lats)
  // 两种经度域宽度：[-180,180] 与 [0,360)
  const lonMinA = Math.min(...lons)
  const lonMaxA = Math.max(...lons)
  const widthA = lonMaxA - lonMinA
  const lons360 = lons.map(to360)
  const lonMinB = Math.min(...lons360)
  const lonMaxB = Math.max(...lons360)
  const widthB = lonMaxB - lonMinB
  const crosses180 = widthA > 180 && widthB <= 360
  return { latMin, latMax, lonMinA, lonMaxA, lonMinB, lonMaxB, crosses180 }
})

function clampToRegion(input: { lng: number; lat: number }) {
  const { latMin, latMax, lonMinA, lonMaxA, lonMinB, lonMaxB, crosses180 } = regionStats.value
  // 纬度直接夹取
  let lat = clamp(input.lat, latMin, latMax)
  let lng: number
  if (!crosses180) {
    // 常规：在 [-180,180] 内夹取
    const x = normLon(input.lng)
    lng = clamp(x, lonMinA, lonMaxA)
    lng = normLon(lng)
  } else {
    // 跨 180°：在 [0,360) 展开域内夹取再还原
    let x360 = to360(normLon(input.lng))
    x360 = clamp(x360, lonMinB, lonMaxB)
    lng = x360 > 180 ? x360 - 360 : x360
  }
  return { lng, lat }
}

// ====== 事件绑定/解绑 ======
function onMapClick(e: mapboxgl.MapMouseEvent & mapboxgl.EventData) {
  const map: Map | undefined = weatherStore.map
  if (!map) return
  const bounded = clampToRegion({ lng: e.lngLat.lng, lat: e.lngLat.lat })
  currentLngLat.value = bounded
  renderFlag(bounded)
}

function bind() {
  const map: Map | undefined = weatherStore.map
  if (!map || listening) return
  map.on('click', onMapClick)
  listening = true
}

function unbind() {
  const map: Map | undefined = weatherStore.map
  if (!map || !listening) return
  map.off('click', onMapClick)
  listening = false
}

// ====== 旗标与弹窗渲染 ======
function ensurePopup(lngLat: LngLatLike) {
  const map: Map | undefined = weatherStore.map
  if (!map || !popupRef.value) return
  if (!popup) {
    popup = new mapboxgl.Popup({
      closeButton: false,
      closeOnClick: false,
      anchor: 'bottom-left',
      offset: [-2, -2],
      className: 'flag-popup-wrapper',
    })
      .setDOMContent(popupRef.value)
      .setLngLat(lngLat)
      .addTo(map)
  } else {
    popup.setLngLat(lngLat)
  }
}

async function renderFlag(lngLat: { lng: number; lat: number }) {
  if (!shown.value) {
    shown.value = true
    await nextTick()
  }
  ensurePopup(lngLat)
  // 防止首次显示时日期面板自动展开
  await nextTick()
  try {
    datePickerRef.value?.handleClose?.()
    datePickerRef.value?.blur?.()
  } catch {}
}

// ====== 对外暴露的方法 ======
function start() {
  active.value = true
  bind()
}

function cancel() {
  unbind()
  if (popup) {
    popup.remove()
    popup = null
  }
  currentLngLat.value = null
  shown.value = false
  active.value = false
  emit('cancel')
}

function query() {
  if (!currentLngLat.value) return
  // 直接使用 form.startTime，无需替换 'T'
  emit('confirm', {
    startTime: form.startTime,
    speed: Number(form.speed),
    duration: Number(form.duration),
    lng: currentLngLat.value.lng,
    lat: currentLngLat.value.lat,
  })
}

// 暴露给父组件
defineExpose({ start, cancel, query })

// 组件卸载时清理
onBeforeUnmount(() => cancel())

// 阻止弹层交互冒泡到地图（拖动地图/双击缩放等）
function stop(e: Event) {
  e.stopPropagation()
}

// 支持点击底部区域（红框）重新定位弹窗
function onPopupBgClick(e: MouseEvent) {
  const map: Map | undefined = weatherStore.map
  if (!map || !active.value || !shown.value) return
  const rect = map.getContainer().getBoundingClientRect()
  const x = e.clientX - rect.left
  const y = e.clientY - rect.top
  const lngLat = map.unproject([x, y])
  const bounded = clampToRegion({ lng: lngLat.lng, lat: lngLat.lat })
  currentLngLat.value = bounded
  ensurePopup(bounded)
}

// ====== 数值输入两位小数限制 ======
function sanitizeTo2Decimals(raw: any): string {
  let s = String(raw ?? '').replace(/[^\d.]/g, '');       // 仅保留数字和点
  const firstDot = s.indexOf('.');
  if (firstDot !== -1) {
    // 仅保留第一个小数点
    s = s.slice(0, firstDot + 1) + s.slice(firstDot + 1).replace(/\./g, '');
    const [i, d = ''] = s.split('.');
    s = i + '.' + d.slice(0, 2);                          // 限制两位小数
  }
  if (s.startsWith('.')) s = '0' + s;                     // 形如 .5 => 0.5
  return s;
}
function handleNumberInput(key: 'speed' | 'duration', val: any) {
  (form as any)[key] = sanitizeTo2Decimals(val);
}
function handleNumberBlur(key: 'speed' | 'duration') {
  const v = Number((form as any)[key]);
  const fixed = isFinite(v) ? Math.max(0, v).toFixed(2) : '0.00';
  (form as any)[key] = fixed;
}
</script>

<template>
  <Teleport to="body">
    <div  element-loading-background="rgba(0,0,0,0.35)" element-loading-text="查询中..." v-if="active && shown" ref="popupRef" class="flag-popup" @mousedown.stop @touchstart.stop @wheel.stop @click="onPopupBgClick">
      <div class="flag-dot"></div>
     <div class="form-cont" @click.stop @mousedown.stop @touchstart.stop @wheel.stop>
       <el-form label-position="left" label-width="90px" class="flag-form">
         <el-form-item label="起航时间：">
           <el-date-picker
             ref="datePickerRef"
             v-model="form.startTime"
             type="datetime"
             format="YYYY/MM/DD HH:mm"
             value-format="YYYY-MM-DD HH:mm"
             :clearable="false"
             :teleported="false"
             :editable="false"
           />
         </el-form-item>
         <el-form-item label="航行速度：">
           <el-input
             v-model="form.speed"
             @input="(val:any) => handleNumberInput('speed', val)"
             @blur="() => handleNumberBlur('speed')"
           >
             <template #suffix>kts</template>
           </el-input>
         </el-form-item>
         <el-form-item label="航行时间：">
           <el-input
             v-model="form.duration"
             @input="(val:any) => handleNumberInput('duration', val)"
             @blur="() => handleNumberBlur('duration')"
           >
             <template #suffix>h</template>
           </el-input>
         </el-form-item>
       </el-form>
       <div class="actions">
         <el-button class="btn ghost" @click="cancel">取消</el-button>
         <el-button type="primary" class="btn primary" @click="query" :loading="loading">确认</el-button>
       </div>
     </div>
    </div>
  </Teleport>
</template>

<style scoped lang="less">
// 统一旗标视觉，与 PointDecoder 保持一致
.flag-popup {
  position: relative;
  box-sizing: border-box;
  min-width: 260px;
  max-width: 320px;
  padding: 10px 12px; // 旗面本体内边距
  padding-bottom: 26px; // 给底部圆点留空间
  background: rgba(0, 0, 0, 0.7); // 深灰旗面
  color: #fff;
  border-left: 2px solid #4d4d4d; // 左侧“旗杆”（与旗面同色，显得整体）
  border-radius: 0 14px 14px 0; // 右侧圆角
  box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
  font-size: 12px;
  user-select: text;
  z-index: 1000;
}

/* 修复：日期面板顶部两个输入框不可见，恢复默认浅色样式（仅限当前弹窗内） */
.flag-popup {
  :deep(.el-picker-panel .el-input__wrapper) {
    background: #fff;
    border-color: #dcdfe6;
    box-shadow: none;
  }
  :deep(.el-picker-panel .el-input__inner) {
    color: #303133;
  }
}

.flag-form {
  :deep(.el-form-item) {
    margin-bottom: 8px;
  }

  :deep(.el-form-item__label){
    color: #FFFFFF;
  }

  :deep(.el-input),
  :deep(.el-input__wrapper),
  :deep(.el-date-editor.el-input),
  :deep(.el-date-editor.el-input__wrapper),
  :deep(.el-input-number .el-input__wrapper) {
    height: 28px;
    box-shadow: none;
    background: rgba(255,255,255,0.06);
    border: 1px solid rgba(255,255,255,0.15);
    border-radius: 4px;
  }
  :deep(.el-input__inner),
  :deep(.el-date-editor .el-input__inner) {
    color: #fff;
  }
  :deep(.el-input__prefix),
  :deep(.el-input__suffix),
  :deep(.el-icon) {
    color: #cfd8dc;
  }
  :deep(.el-input-number) {
    width: 110px;
  }
}

:deep(.el-button.btn) {
  min-width: 70px;
  height: 30px;
  padding: 0 12px;
  border-radius: 6px;
}
:deep(.el-button.btn.ghost) {
  background: rgba(255,255,255,0.06);
  border-color: rgba(255,255,255,0.25);
  color: #fff;
}
:deep(.el-button.btn.primary) {
  background: #1677ff;
  border-color: #1677ff;
  color: #fff;
}

/* 模拟旗面箭头（容器自身不含，交给 mapbox 的箭头；此处作为兼容/美化） */
:deep(.mapboxgl-popup-content) {
  padding: 0 !important;
  background: transparent;
  border-radius: 0;
}
:deep(.mapboxgl-popup) { z-index: 1000; }
:deep(.mapboxgl-popup-tip) { display: none; } // 隐藏默认三角形箭头

.flag-dot {
  position: absolute;
  width: 8px;
  height: 8px;
  background-color: #fff;
  border-radius: 50%;
  left: -5px;  // 略微“探出”左侧，贴近旗杆
  bottom: -5px; // 略微超出底部
  box-shadow: 0 0 0 2px rgba(0,0,0,0.15);
}

.row {
  display: flex;
  align-items: center;
  margin-bottom: 8px;
}
.label {
  width: 72px;
  color: #cfd8dc;
}
.input {
  flex: 1;
  height: 28px;
  padding: 0 8px;
  border-radius: 4px;
  border: 1px solid rgba(255, 255, 255, 0.15);
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
  outline: none;
}
.input.number {
  width: 80px;
  flex: 0 0 auto;
}
.unit {
  margin-left: 6px;
  color: #90a4ae;
}
.actions {
  display: flex;
  justify-content: space-between;
  margin-top: 10px;
}
.btn {
  min-width: 70px;
  height: 30px;
  border-radius: 6px;
  border: 1px solid rgba(255, 255, 255, 0.25);
  background: transparent;
  color: #fff;
  cursor: pointer;
}
.btn.ghost {
  background: rgba(255, 255, 255, 0.06);
}
.btn.primary {
  background: #1677ff;
  border-color: #1677ff;
}
.btn:active {
  opacity: 0.9;
}

:deep(.flag-popup-wrapper) { max-width: none !important; }
</style>

<style>
.flag-popup-wrapper {
  z-index: 999;

  .mapboxgl-popup-tip {
    display: none;
  }
  .mapboxgl-popup-content {
    background: transparent;
    box-shadow: none;

  }

  .flag-popup {
    height: 230px;
    background-color: transparent;
    box-shadow: none;
    padding: 0;
    transform: translate(-10px,15px);

    .form-cont {
     background: rgba(0, 0, 0, 0.8);
      padding:20px;
      width: 300px;
      border-top-right-radius: 10px;
      border-bottom-right-radius: 10px;
    }
  }

}
</style>
